/*
 * Wazuh Vulnerability scanner - Scan Orchestrator
 * Copyright (C) 2015, Wazuh Inc.
 * Jun 1, 2023.
 *
 * This program is free software; you can redistribute it
 * and/or modify it under the terms of the GNU General Public
 * License (version 2) as published by the FSF - Free Software
 * Foundation.
 */

#ifndef _INVENTORY_SYNC_HPP
#define _INVENTORY_SYNC_HPP

#include "../policyManager/policyManager.hpp"
#include "chainOfResponsability.hpp"
#include "rocksDBWrapper.hpp"
#include "scanContext.hpp"
#include "timeHelper.h"

constexpr auto OS = "os";
constexpr auto PACKAGE = "package";
constexpr auto OS_INITIAL_SCAN = "os_initial_scan";

const std::map<AffectedComponentType, std::string> AFFECTED_COMPONENT_COLUMNS = {
    {AffectedComponentType::Os, OS}, {AffectedComponentType::Package, PACKAGE}};

/**
 * @brief TInventorySync class.
 * This class is in charge of synchronizing the inventory database.
 *
 * @tparam TScanContext scan context type.
 */
template<typename TScanContext = ScanContext>
class TInventorySync
{
protected:
    Utils::RocksDBWrapper& m_inventoryDatabase; ///< Inventory database.

    /**
     * @brief Elements to process.
     * @param operation Operation.
     * @param elementKey Element key.
     * @return nlohmann::json Element to process.
     */
    static nlohmann::json buildElement(const std::string& operation, const std::string& elementKey)
    {
        nlohmann::json json;
        json["operation"] = operation;
        json["id"] = elementKey;
        return json;
    }

    /**
     * @brief Get the affected component key.
     *
     * @param data Scan context.
     * @return std::string_view Affected component key.
     */
    std::string_view affectedComponentKey(const std::shared_ptr<TScanContext>& data)
    {
        if (data->affectedComponentType() == AffectedComponentType::Os)
        {
            return data->osName();
        }
        else if (data->affectedComponentType() == AffectedComponentType::Package)
        {
            return data->packageItemId();
        }
        else
        {
            throw std::runtime_error("Invalid affected type for inventory sync.");
        }
    }

public:
    // LCOV_EXCL_START
    /**
     * @brief InventorySync constructor.
     *
     * @param inventoryDatabase Inventory database.
     */
    explicit TInventorySync(Utils::RocksDBWrapper& inventoryDatabase)
        : m_inventoryDatabase(inventoryDatabase)
    {
        for (const auto& element : AFFECTED_COMPONENT_COLUMNS)
        {
            if (!m_inventoryDatabase.columnExists(element.second))
            {
                m_inventoryDatabase.createColumn(element.second);
            }
        }

        if (!m_inventoryDatabase.columnExists(OS_INITIAL_SCAN))
        {
            m_inventoryDatabase.createColumn(OS_INITIAL_SCAN);
        }
    }
    // LCOV_EXCL_STOP
};

using InventorySync = TInventorySync<>;

#endif // _INVENTORY_SYNC_HPP
